/**
 * 轻量级JS模块化加载管理
 * Author: 陆楚良
 * Version: 1.1.2
 * Date: 2014-01-27
 * QQ: 519998338
 *
 * https://git.oschina.net/luchg/Glight.js.git
 *
 * License: http://opensource.org/licenses/MIT
 */
!function(window, document, undefined){

var GlightJS = {version:"1.1.2"};

function isType(type) {
  return function(obj) {
    return {}.toString.call(obj) == "[object " + type + "]"
  }
}
var isObject = isType("Object");
var isString = isType("String");
var isFunction = isType("Function");
var isArray = Array.isArray || isType("Array");


var RE_REQUIRE = /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\/\*[\S\s]*?\*\/|\/(?:\\\/|[^\/\r\n])+\/(?=[^\/])|\/\/.*|\.\s*require|(?:^|[^$])\brequire\s*\(\s*(["'])(.+?)\1\s*\)/g;
var RE_BASE = new RegExp(RE_REQUIRE.source.replace(/require/g,"base"));
var RE_SLASH = /\\\\/g;
var RE_EXT = /[\?#].*/;
var RE_SEP = /\\/g;
var RE_DIR = /[^?#]*\//;
var RE_VARS= /{([^{]+)}/g;


/*head节点*/
var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement;
/*base节点*/
var baseElement = head.getElementsByTagName("base")[0];
/*老版本webkit*/
var isOldWebKit = +navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/(\d+).*/, "$1") < 536;
var loadQ = {};

var _debug_load_   = "load:";
var _debug_done_   = "done:";
var _debug_finish_ = "finish:";
var _debug_compile_= "compile:";
var _debug_require_= "require:";
var _debug_save_   = "save:";
var _debug_define_ = "define:";
var _debug_color_  = {};
_debug_color_[_debug_load_]   = "black";
_debug_color_[_debug_done_]   = "green";
_debug_color_[_debug_finish_] = "gray";
_debug_color_[_debug_compile_]= "Orchid";
_debug_color_[_debug_require_]= "green";
_debug_color_[_debug_save_]   = "blue";
_debug_color_[_debug_define_] = "peru";
var debug = function(t, m, o){
	var console = window.console||{};
	if(Conf.debug && isFunction(console.log)){
		switch(t){
			case _debug_require_:
			case _debug_define_:
				console.log("%c"+t+"%O"+m, "color:"+_debug_color_[t], o);
				break;
			default:
				console.log("%c"+t+m, "color:"+_debug_color_[t]);
		}
	}
};

var currentlyAddingScript;
var interactiveScript;
//加载资源
function loadResource(url, onload){
	var absPath = getAbsPath(url);
	if(absPath in loadQ){
		loadQ[absPath].queue(function(){
			debug(_debug_finish_, absPath);
			setTimeout(onload, 1);
			loadQ[absPath].dequeue();
		});
		return;
	}
	debug(_debug_load_, absPath);
	var ext  = url.split(/\./).pop();
	var isCSS = (ext.replace(RE_EXT, '').toLowerCase()=="css");
	var node = document.createElement(isCSS?"link":"script");
	if(isCSS){
		node.rel = "stylesheet";
		node.href= url;
	}else{
	    node.async = true;
	    node.src = url;
	}
	if(Conf.charset)node.charset = Conf.charset;
	var supportOnload = "onload" in node;
	loadQ[absPath] = Queue();
	loadQ[absPath].queue(function(){
		var done = function(){
				node.onload = node.onreadystatechange = null;
				!isCSS && !Conf.debug && head.removeChild(node);
				debug(_debug_done_, absPath);
				setTimeout(function(){onload(absPath, isCSS, node);node=null}, 1);
				loadQ[absPath].dequeue();
			};
		if(isCSS && (isOldWebKit || !supportOnload)){
			setTimeout(function(){pollCss(node,done)},1);
		}
		else if(supportOnload){
			node.onload = done;
			node.onerror=function(){done()};
		}
		else{
			node.onreadystatechange = function() {
				if (/loaded|complete/.test(node.readyState)) {
					done();
				}
			}
		}
		currentlyAddingScript = node;
		baseElement ? head.insertBefore(node, baseElement) : head.appendChild(node);
		currentlyAddingScript = null;
	});
}

// 轮询监视css加载
function pollCss(node,callback){
	var sheet = node.sheet,
		isLoaded;
	if (isOldWebKit) {
		if (sheet) {
			isLoaded = true;
		}
	}
	else if (sheet) {
		try {
			if (sheet.cssRules) {
				isLoaded = true;
			}
		} catch (e) {
			if (e.name === "NS_ERROR_DOM_SECURITY_ERR") {
				isLoaded = true;
			}
		}
	}
	isLoaded ? callback() : setTimeout(function() {pollCss(node, callback)}, 100);
}

var AbsPathElement = document.createElement("a");
function getAbsPath(node){
	if(isString(node)){
		AbsPathElement.href = node;
		return AbsPathElement.hasAttribute ? AbsPathElement.href : AbsPathElement.getAttribute("href", 4);
	}
	return node.hasAttribute ? node.src : node.getAttribute("src", 4);
}

function getCurrAbsPath() {
	if (currentlyAddingScript) {
		return getAbsPath(currentlyAddingScript);
	}
	if (interactiveScript && interactiveScript.readyState === "interactive") {
		return getAbsPath(interactiveScript);
	}
	// FF,Chrome
	if (document.currentScript){
		return document.currentScript.src;
	}
	// IE 5-10
	var scripts = head.getElementsByTagName("script")
	for (var i = scripts.length - 1; i >= 0; i--) {
		var script = scripts[i]
		if (script.readyState === "interactive") {
			interactiveScript = script;
			return getAbsPath(interactiveScript);
		}
	}
}


// 简单的队列引擎
function Queue(){
	var Q={
		l:[],c:1,
		queue:function(callback){
			Q.l.push(callback);
			Q.c && Q.dequeue();
			return Q;
		},
		dequeue:function(){
			Q.c = 0;
			var s = Q.l.shift();
	        if(s){
	        	isFunction(s) && s.call(Q);
	        }else{
	            Q.c = 1;
	        }
	        return Q;
		}
	};
	return Q;
}

function dirname(path){
	return path ? path.match(RE_DIR)[0] : "";
}

// 事件
var EVENT_LOAD = {},EVENTS={};
function Event(name, callback){
	if(callback){
		if(name in EVENT_LOAD){
			callback();
		}else{
			if(name in EVENTS)
				EVENTS[name].push(callback);
			else
				EVENTS[name] = [callback];
		}
	}
	else{
		EVENT_LOAD[name] = true;
		if(name in EVENTS){
			for(var i=0;i<EVENTS[name].length;i++){
				setTimeout(EVENTS[name][i], 1);
			}
		}
	}
}

function parseDeps(factoryStr){
	var ret=[];
	factoryStr.replace(RE_SLASH, "").replace(RE_REQUIRE, function(a, a1, a2) {a2 && ret.push(a2)});
	return ret;
}
function parseURI(uri, dir){
	// 如果设置别名时，使用别名
	if(isString(Conf.alias[uri])){
		uri = parseURI(Conf.alias[uri]);
	}
	// 解析变量配置
	if (Conf.vars && uri.indexOf("{") > -1) {
		uri = uri.replace(RE_VARS, function(m, k) {
			return isString(Conf.vars[k]) ? Conf.vars[k] : m;
		});
	}
	var i,ext = uri.toLowerCase().split(/\./).pop();
	p = ext.replace(RE_EXT, '');
	uri = uri.replace(RE_SEP, "/");
	uri = (p==ext && p!="css" && p!="js") ? uri+Conf.suffix : uri;
	if(!/^(https?:)?\/\//.test(uri)){
		uri = dir+uri;
	}
	return uri;
}

var cacheMod= {};
function require(uri, dir){
	var m,exp,
		exports={},
		meta = cacheMod[getAbsPath(parseURI(uri, dir))];
	if(meta){
		if("exports" in meta){
			exp = meta.exports;
		}else{
			if(isFunction(meta.factory)){
				debug(_debug_compile_, meta.uri);
				m = {
					uri:meta.uri,
					dependencies:meta.deps,
					exports:exports
				};
				var _require = function(uri){return require(uri, meta.dir)};
				_require.async = function(uri, callback){
					return GlightJS.use(parseURI(uri, meta.dir), callback);
				};
				exp = meta.factory.call(window, _require, exports, m);
				if(exp===undefined){
					if(exports!==m.exports){
						exp = m.exports;
					}else{
						for(exp in exports){exp=exports;break;}
					}
				}
			}else{
				exp = meta.factory;
			}
			meta.exports = exp;
		}
		debug(_debug_require_, meta.uri, meta);
	}
	return exp;
}
function onloadModule(meta){
	debug(_debug_save_, meta.uri);
	cacheMod[meta.uri]= meta;
	Event(meta.uri);
}

var anonymousMeta;
function loadModule(uri){
	cacheMod[uri] || loadResource(uri, function(absPath, isCSS, node){
		// css文件没有代码，因此没有走define，因此无需解析直接存入模块
		if(isCSS){
			onloadModule({uri: absPath, dir: dirname(absPath), deps: [], factory: node});
		}else if(anonymousMeta){
			anonymousMeta.uri = absPath;
			anonymousMeta.dir = dirname(absPath);
			debug(_debug_define_, absPath, anonymousMeta.deps);
			saveModule(anonymousMeta);
			anonymousMeta = null;
		}
	});
}
function saveModule(meta, callback){
	var Q = Queue();
	for(i=0; i<meta.deps.length; i++){
		!function(i){
			Q.queue(function(){
				var absPath = getAbsPath( parseURI(meta.deps[i], meta.dir) );
				loadModule(absPath);
				Event(absPath, function(){
					Q.dequeue();
				});
			});
		}(i);
	}
	Q.queue(function(){
		callback ? callback() : onloadModule(meta);
		Q.dequeue();
	});
}

function define(factory){
	var deps = isFunction(factory) ? parseDeps(factory.toString()) : [];
	var meta = {
		uri: getCurrAbsPath(),
		deps:deps,
		factory:factory
	};
	if(meta.uri){
		meta.dir = dirname(meta.uri);
		debug(_debug_define_, meta.uri, deps);
		saveModule(meta);
	}else{
		// 个别浏览器没有抓到当前uri，如Safari，使用onload方法
		anonymousMeta = meta;
	}
}
var scripts = document.scripts;
var Conf = {
	alias: {},
	vars : undefined,
	base : dirname(getAbsPath(document.getElementById("glight-js-node") || scripts[scripts.length - 1])),
	suffix : ".js",
	charset: undefined,
	cache  : cacheMod,
	debug  : false
};

GlightJS.config = function(name,value){
	var argsLen = arguments.length;
	if(argsLen==1){
		if(isString(name)){
			return Conf[name];
		}else if(isObject(name)){
			for(var i in name){
				if(i in Conf && i!='cache')Conf[i] = name[i];
			}
		}
	}else if(name in Conf){
		Conf[name] = value;
	}
};
GlightJS.use = function(deps, callback){
	if(!isArray(deps)){
		deps = [deps];
	}
	var meta = {
		uri:undefined,
		dir:Conf.base,
		deps:deps
	}
	saveModule(meta, function(){
		var r = [];
		for(var i=0; i<deps.length; i++){
			r.push(require(deps[i], meta.dir));
		}
		isFunction(callback) && callback.apply(window, r);
	});
	return this;
};
define.cmd = {};
window.define = define;
window.GlightJS= GlightJS;
}(window, document);